{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'original': 'completion', 'parsed': 'noitelpmoc'}"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import (\n",
    "    RunnableLambda,\n",
    "    RunnableParallel,\n",
    "    RunnablePassthrough,\n",
    ")\n",
    "\n",
    "runnable = RunnableParallel(\n",
    "    origin=RunnablePassthrough(),\n",
    "    modified=lambda x: x+1\n",
    ")\n",
    "\n",
    "runnable.invoke(1) # {'origin': 1, 'modified': 2}\n",
    "\n",
    "\n",
    "def fake_llm(prompt: str) -> str: # Fake LLM for the example\n",
    "    return \"completion\"\n",
    "\n",
    "chain = RunnableLambda(fake_llm) | {\n",
    "    'original': RunnablePassthrough(), # Original LLM output\n",
    "    'parsed': lambda text: text[::-1] # Parsing logic\n",
    "}\n",
    "\n",
    "chain.invoke('hello') # {'original': 'completion', 'parsed': 'noitelpmoc'}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### RunablePassthrough"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'llm1': 'completion', 'llm2': 'completion', 'total_chars': 20}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.runnables import RunnablePassthrough\n",
    "\n",
    "def fake_llm(prompt: str) -> str: # Fake LLM for the example\n",
    "    return \"completion\"\n",
    "\n",
    "runnable = {\n",
    "    'llm1':  fake_llm,\n",
    "    'llm2':  fake_llm,\n",
    "} | RunnablePassthrough.assign(\n",
    "    total_chars=lambda inputs: len(inputs['llm1'] + inputs['llm2'])\n",
    ")\n",
    "\n",
    "runnable.invoke('hello')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### configurable_fields "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "Configuration key temperature not found in client=<class 'dashscope.aigc.generation.Generation'> dashscope_api_key=SecretStr('**********'): available keys are dict_keys(['name', 'cache', 'verbose', 'callbacks', 'tags', 'metadata', 'custom_get_token_ids', 'callback_manager', 'client', 'model_name', 'model_kwargs', 'top_p', 'dashscope_api_key', 'streaming', 'max_retries'])",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[20], line 13\u001b[0m\n\u001b[0;32m      9\u001b[0m os\u001b[38;5;241m.\u001b[39menviron[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDASHSCOPE_API_KEY\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msk-c78e46dbb3824fd2bb26c3bcd4bbc2a6\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m     11\u001b[0m \u001b[38;5;66;03m#set_debug(True)  # 启用 langchain 的调试模式\u001b[39;00m\n\u001b[1;32m---> 13\u001b[0m model \u001b[38;5;241m=\u001b[39m \u001b[43mChatTongyi\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtemperature\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0.8\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfigurable_fields\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m     14\u001b[0m \u001b[43m    \u001b[49m\u001b[43mtemperature\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mConfigurableField\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m     15\u001b[0m \u001b[43m        \u001b[49m\u001b[38;5;28;43mid\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mllm_temperature\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m     16\u001b[0m \u001b[43m        \u001b[49m\u001b[43mname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mLLM Temperature\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m     17\u001b[0m \u001b[43m        \u001b[49m\u001b[43mdescription\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mThe temperature of the LLM\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m     18\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     19\u001b[0m \u001b[43m)\u001b[49m\n\u001b[0;32m     21\u001b[0m resposne_0 \u001b[38;5;241m=\u001b[39m model\u001b[38;5;241m.\u001b[39minvoke(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpick a random number\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m     22\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mresposne_0 >> \u001b[39m\u001b[38;5;124m'\u001b[39m, resposne_0)\n",
      "File \u001b[1;32md:\\Program Files\\Python\\Python311\\Lib\\site-packages\\langchain_core\\runnables\\base.py:2065\u001b[0m, in \u001b[0;36mRunnableSerializable.configurable_fields\u001b[1;34m(self, **kwargs)\u001b[0m\n\u001b[0;32m   2063\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m key \u001b[38;5;129;01min\u001b[39;00m kwargs:\n\u001b[0;32m   2064\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m key \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__fields__:\n\u001b[1;32m-> 2065\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m   2066\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConfiguration key \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkey\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m not found in \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m   2067\u001b[0m             \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mavailable keys are \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m__fields__\u001b[38;5;241m.\u001b[39mkeys()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m   2068\u001b[0m         )\n\u001b[0;32m   2070\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m RunnableConfigurableFields(default\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m, fields\u001b[38;5;241m=\u001b[39mkwargs)\n",
      "\u001b[1;31mValueError\u001b[0m: Configuration key temperature not found in client=<class 'dashscope.aigc.generation.Generation'> dashscope_api_key=SecretStr('**********'): available keys are dict_keys(['name', 'cache', 'verbose', 'callbacks', 'tags', 'metadata', 'custom_get_token_ids', 'callback_manager', 'client', 'model_name', 'model_kwargs', 'top_p', 'dashscope_api_key', 'streaming', 'max_retries'])"
     ]
    }
   ],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain_community.chat_models import ChatOpenAI\n",
    "from langchain_core.runnables import ConfigurableField\n",
    "from langchain.globals import set_debug  # 导入在 langchain 中设置调试模式的函数\n",
    "from langchain_community.chat_models.tongyi import ChatTongyi\n",
    "from dotenv import load_dotenv  # 导入从 .env 文件加载环境变量的函数\n",
    "load_dotenv()  # 调用函数实际加载环境变量\n",
    "\n",
    "os.environ[\"DASHSCOPE_API_KEY\"] = \"sk-c78e46dbb3824fd2bb26c3bcd4bbc2a6\"\n",
    "\n",
    "#set_debug(True)  # 启用 langchain 的调试模式\n",
    "\n",
    "model = ChatTongyi(temperature=0.8).configurable_fields(\n",
    "    temperature=ConfigurableField(\n",
    "        id=\"llm_temperature\",\n",
    "        name=\"LLM Temperature\",\n",
    "        description=\"The temperature of the LLM\",\n",
    "    )\n",
    ")\n",
    "\n",
    "resposne_0 = model.invoke(\"pick a random number\")\n",
    "print('resposne_0 >> ', resposne_0)\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.tools import tool\n",
    "@tool\n",
    "def f(x: str) -> str:\n",
    "    return x + \"a\"\n",
    "@tool\n",
    "def g(x: str) -> str:\n",
    "    return x + \"z\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts.chat import BaseChatPromptTemplate\n",
    "from langchain.schema import (\n",
    "    AgentAction,\n",
    "    AgentFinish,\n",
    "    AIMessage,\n",
    "    HumanMessage,\n",
    "    OutputParserException,\n",
    "    SystemMessage,\n",
    ")\n",
    "from langchain.tools.base import BaseTool\n",
    "from typing import Any, List, Sequence, Tuple, Union\n",
    "import re\n",
    "\n",
    "class QwenChatAgentPromptTemplate(BaseChatPromptTemplate):\n",
    "    # The template to use\n",
    "    template: str\n",
    "    # The list of tools available\n",
    "    tools: List[BaseTool]\n",
    "\n",
    "    def format_messages(self, **kwargs) -> str:\n",
    "        # Get the intermediate steps (AgentAction, Observation tuples)\n",
    "        # Format them in a particular way\n",
    "        intermediate_steps = kwargs.pop(\"intermediate_steps\", [])\n",
    "        thoughts = \"\"\n",
    "        for action, observation in intermediate_steps:\n",
    "            thoughts += action.log\n",
    "            thoughts += f\"\\nObservation: {observation}\\nThought: \"\n",
    "        # Set the agent_scratchpad variable to that value\n",
    "        if thoughts:\n",
    "            kwargs[\n",
    "                \"agent_scratchpad\"\n",
    "            ] = f\"These were previous tasks you completed:\\n{thoughts}\\n\\n\"\n",
    "        else:\n",
    "            kwargs[\"agent_scratchpad\"] = \"\"\n",
    "        # Create a tools variable from the list of tools provided\n",
    "\n",
    "        tools = []\n",
    "        for t in self.tools:\n",
    "            desc = re.sub(r\"\\n+\", \" \", t.description)\n",
    "            text = (\n",
    "                f\"{t.name}: Call this tool to interact with the {t.name} API. What is the {t.name} API useful for?\"\n",
    "                f\" {desc}\"\n",
    "                f\" Parameters: {t.args}\"\n",
    "            )\n",
    "            tools.append(text)\n",
    "        kwargs[\"tools\"] = \"\\n\\n\".join(tools)\n",
    "        # kwargs[\"tools\"] = \"\\n\".join([str(format_tool_to_openai_function(tool)) for tool in self.tools])\n",
    "        # Create a list of tool names for the tools provided\n",
    "        kwargs[\"tool_names\"] = \", \".join([tool.name for tool in self.tools])\n",
    "        formatted = template.format(**kwargs)\n",
    "        return [HumanMessage(content=formatted)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[HumanMessage(content='\\n这是一个测试模板。\\n问题：你好\\n\\n')]"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tools = []\n",
    "template = \"\"\"\n",
    "这是一个测试模板。\n",
    "问题：{input}\n",
    "\n",
    "\"\"\"\n",
    "prompt = QwenChatAgentPromptTemplate(\n",
    "    input_variables=[\"input\", \"intermediate_steps\"], template=template, tools=tools\n",
    ")\n",
    "prompt.format_messages(input=\"你好\", intermediate_steps=[])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
